package com.yilin.platform.base_core.commons.utils;

import com.yilin.platform.base_core.tools.pab.base.XmlField;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.function.Consumer;
import java.util.logging.Logger;

public class FieldUtil {
    private static Logger logger = Logger.getLogger(FieldUtil.class.getName());

    public interface IAniQuery<T> {
        public boolean callback(T ann);
    }

    /*
     * 根据属性名获取属性类型
     * */
    public static Class getFiledType(String fieldName, Class clazz) {
        ArrayList<Field> list = new ArrayList<>(Arrays.asList(clazz.getDeclaredFields()));
        for (; clazz != Object.class; clazz = clazz.getSuperclass()) {//向上循环 遍历父类
            list.addAll(Arrays.asList(clazz.getDeclaredFields()));
        }
        for (Field field : list) {
            if (Objects.equals(fieldName, field.getName())) {
                return field.getType();
            }
        }
        return null;
    }

    public static Field getField(Class c, String fieldName) {
        Field javaField = null;
        try {
            if (FieldUtil.hasField(c, fieldName)) {
                javaField = c.getDeclaredField(fieldName);
            } else {
                for (; c != Object.class && javaField == null; c = c.getSuperclass()) {//向上循环 遍历父类
                    if (FieldUtil.hasField(c, fieldName)) {
                        javaField = c.getDeclaredField(fieldName);
                    }
                }
            }
        } catch (NoSuchFieldException e) {
            return null;
        }
        return javaField;
    }

    public static List<Field> getFields(Class c) {
        List<Field> javaFields = new ArrayList<>(Arrays.asList(c.getDeclaredFields()));
        for (; c != Object.class; c = c.getSuperclass()) {//向上循环 遍历父类
            ArrayUtil.notRepeatAddAll(javaFields, Arrays.asList(c.getDeclaredFields()));
        }
        return javaFields;
    }


    private static boolean hasField(Class c, String fieldName) {
        Field[] fields = c.getDeclaredFields();
        for (Field f : fields) {
            if (fieldName.equals(f.getName())) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取实例化名称
     * 查询工具类
     */
    public static String getObjName(Class cls) {
        String objName = cls.getName();
        if (objName.contains(".")) {
            String[] splits = objName.split("\\.");
            objName = splits[splits.length - 1];
            objName = StringUtil.toLowerCaseFirstOne(objName);
        }
        return objName;
    }

    /**
     * 获取注解字段
     */
    public static List<Field> getFieldsByAnnotation(Class cls, Class<? extends Annotation> a) {
        List<Field> fields = getFields(cls);
        List<Field> list = new ArrayList<>();
        for (Field field : fields) {
            Annotation column = field.getAnnotation(a);
            if (column == null) continue;
            list.add(field);
        }
        return list;
    }

    /**
     * 反向 查询值 Annotation=Value
     */
    public static <T, V extends Annotation> Field queryFiledByAnnValue(Class<T> objClass, Class<V> annCls, IAniQuery<V> query) {
        List<Field> fields = FieldUtil.getFieldsByAnnotation(objClass, annCls);
        for (Field field : fields) {
            V annotation = field.getAnnotation(annCls);
            if (query.callback(annotation)) return field;
        }
        return null;
    }

    /**
     * 操作对象SET
     */
    public static <T> T objSet(T o, Field field, Object value) {
        try {
            field.setAccessible(true); // 打破封装
            if (Modifier.isStatic(field.getModifiers())) return o; // 跳过静态属性
            if (value == null) {
                field.set(o, null);
            } else if (field.getType().equals(Date.class)) {
                if (value instanceof Long) {
                    field.set(o, new Date((Long) value));
                } else if (value instanceof String) {
                    field.set(o, DateTimeUtil.stringToDate((String) value, null));
                } else field.set(o, value);
            } else if (field.getType().isEnum()) {
                Object[] objects = field.getType().getEnumConstants();
                field.set(o, objects[(int) value]);
            } else {
                field.set(o, value);
            }
            return o;
        } catch (Exception e) {
            logger.warning(o.getClass().getName() + ": [ERROR] 属性'" + field.getName() + "'SET失败.");
        }
        return o;
    }

    /**
     * 返回对象GET
     */
    public static Object objGet(Object o, Field field) {
        if (o == null) return null;
        try {
            field.setAccessible(true); // 打破封装
            return field.get(o);
        } catch (Exception e) {
            logger.warning(o.getClass().getName() + ": [ERROR] 属性'" + field.getName() + "'GET失败.");
        }
        return null;
    }

    /**
     * copy
     */
    public static <T> T copy(T o, Class<T> j) {
        if (o == null || j == null) return null;
        try {
            T t = j.newInstance();
            List<Field> fieldList = getFields(o.getClass());
            fieldList.forEach(field -> {
                Object value = objGet(o, field);
                objSet(t, getField(j, field.getName()), value);
            });
            return t;
        } catch (Exception e) {
            logger.warning(o.getClass().getName() + " 到 " + j.getName() + " 复制失败！");
        }
        return null;
    }


}
